import { View, Image, ImageProps } from '@tarojs/components';
import { useCallback, useEffect, useState } from 'react';
import Loading from 'pd-taro-ui/Loading';
import Icon from 'pd-taro-ui/Icon';
import Text from 'pd-taro-ui/Text';
import Grid from 'pd-taro-ui/Grid';
import Column from 'pd-taro-ui/Column';
import './index.scss';
import { useReactive } from 'ahooks';
import classNames from 'classnames';
import {
  chooseFileByType,
  chooseFileByTypes,
  extractFilename,
  getDefaultOnUploadRequest,
  getFileExtension,
  imageAccepts,
  transSelectedValueToValue,
  transValueToSelectedValue,
} from './utils';
import Taro from '@tarojs/taro';
import { previewFile } from '@/utils/platform';
import { Button } from 'pd-taro-ui';

export interface FileItem {
  id?: string;
  value?: string;
  name?: string;
  [key: string]: any;
}

export type SelectType = 'image' | 'video' | 'file';

export interface UploadFileProps {
  value?: string | string[] | FileItem[];
  onChange?: (value: UploadFileProps['value']) => any;
  onBlur?: any;
  placeholder?: string;
  staticed?: boolean;
  disabled?: boolean;
  compProps?: any;
  className?: string;
  /** 是否显示清除按钮 */
  clearable?: boolean;
  /** 限制可选择的文件类型, 请配置此属性为文件后缀.csv,.md*/
  accept?: string;
  selectTypes?: SelectType[];
  /** 最大数量 */
  maxLength?: number;
  /** 是否拼接字符串，返回数组或字符串，默认true字符串 */
  joinValues?: boolean;
  /** 字符串拼接符号，默认, */
  delimiter?: string;
  /** 渲染标签：默认label */
  labelField?: string;
  /** 文件的值用那个字段来标识：默认value */
  valueField?: string;
  /** 是否将value值抽取出来组成新的数组，只有在joinValues是false是生效, 默认false */
  extractValue?: boolean;
  /** 文件下载地址的字段名。没有就读取valueField */
  urlField?: string;
  /** 上传按钮的文字 */
  btnLabel?: string;
  /** 展示类型：默认picture-card"*/
  listType?: 'picture-card' | 'text';
  /** 一行多少列，默认4 , 卡片形式支持 */
  column?: number;
  /** 上传文件的请求方法，返回一个promise，参数为文件的路径，返回一个文件的url */
  onUploadRequest?: (file: string | object) => Promise<string>;
  onBeforeAdd?: (items: FileItem[]) => Promise<any>;
  /** 上传文件成功后的回调通知 */
  onAfterUploadSuccess?: (item: FileItem, items: FileItem[]) => any;
  /** 删除文件之前操作 */
  onBeforeDelete?: (index: number, item: FileItem, items: FileItem[]) => Promise<any>;
  /** 删除文件之后操作 */
  onAfterDelete?: (index: number, item: FileItem, items: FileItem[]) => any;
}
const UploadFile = ({
  onChange,
  value,
  disabled,
  staticed,
  onBlur,
  clearable = false,
  placeholder = '请选择',
  className,
  compProps,
  accept,
  selectTypes = ['image', 'video', 'file'],
  joinValues = true,
  delimiter = ',',
  labelField = 'label',
  valueField = 'value',
  extractValue = false,
  urlField = '',
  btnLabel = '上传文件',
  listType = 'picture-card',
  column = 4,
  maxLength = -1,
  onBeforeAdd,
  onUploadRequest,
  onAfterUploadSuccess,
  onBeforeDelete,
  onAfterDelete,
  ...props
}: UploadFileProps) => {
  const state = useReactive({
    show: false,
    selectedValue: [] as FileItem[],
    searchStr: '',
  });

  const editable = !disabled && !staticed;

  const submit = () => {
    onChange?.(transSelectedValueToValue(state.selectedValue, joinValues, delimiter, valueField, extractValue));
  };

  const clear = () => {
    state.selectedValue = [];
    submit();
  };

  const add = async () => {
    try {
      if (!onUploadRequest) {
        onUploadRequest = getDefaultOnUploadRequest();
        if (!onUploadRequest) {
          return Taro.showToast({
            title: '请先设置onUploadRequest',
            icon: 'none',
          });
        }
      }
      await onBeforeAdd?.(state.selectedValue.concat());
      chooseFileByTypes({
        selectTypes: ['image', 'video', 'file'],
        accept,
      })
        .then(async file => {
          if (!file) {
            return;
          }
          let filePath = '';
          if (typeof file === 'string') {
            filePath = file;
          } else if (process.env.TARO_ENV === 'h5') {
            // File {name: '11.xls', lastModified: 1709514071567, lastModifiedDate: Mon Mar 04 2024 09:01:11 GMT+0800 (中国标准时间), webkitRelativePath: '', size: 18944
            filePath = (file as any).name;
          }
          console.log('chooseFileByType', { file, filePath });
          // 上传文件
          const result = await onUploadRequest!(file);
          // const result = await upload('/image',file)
          const fileItem: FileItem = {
            id: new Date().getTime().toString(),
            [labelField]: extractFilename(filePath),
            [valueField]: result,
            [urlField || valueField]: result,
          };
          state.selectedValue.push(fileItem);
          submit();
          onAfterUploadSuccess?.(fileItem, state.selectedValue.concat());
        })
        .catch(e => {
          console.log(e);
          Taro.showToast({
            title: JSON.stringify(e),
            icon: 'none',
          });
        });
    } catch (e) {
      console.log(e);
      Taro.showToast({
        title: JSON.stringify(e),
        icon: 'none',
      });
    }
  };

  const del = async (index: number) => {
    try {
      await onBeforeDelete?.(index, state.selectedValue[index], state.selectedValue.concat());
      state.selectedValue.splice(index, 1);
      submit();
      onAfterDelete?.(index, state.selectedValue[index], state.selectedValue.concat());
    } catch (error) {
      Taro.showToast({
        title: JSON.stringify(error),
        icon: 'none',
      });
    }
  };

  const preview = (index: number) => {
    const item = state.selectedValue[index];
    const src = item[urlField || valueField];
    const extension = getFileExtension(src) || '';
    const isImage = imageAccepts.includes(extension);
    if (isImage) {
      Taro.previewImage({
        urls: state.selectedValue.map(v => v[urlField || valueField]),
        current: state.selectedValue[index][urlField || valueField],
      });
    } else {
      previewFile(src);
    }
  };

  useEffect(() => {
    // value变化监听
    const selectedValue = transValueToSelectedValue(value, joinValues, delimiter, labelField, valueField, urlField);
    if (selectedValue.map(v => v[valueField]).join(delimiter) !== state.selectedValue.map(v => v[valueField]).join(delimiter)) {
      state.selectedValue = selectedValue;
    }
  }, [value]);

  const canUpload = editable && (maxLength === -1 || state.selectedValue.length < maxLength);
  return (
    <View className={classNames({ 'pd-UploadFile': true })}>
      {listType === 'picture-card' && (
        <Grid column={column} square gap={24}>
          {state.selectedValue?.map((item, index) => {
            const src = item[urlField || valueField];
            const extension = getFileExtension(src) || '';
            const isImage = imageAccepts.includes(extension);
            return (
              <View className='pd-UploadFile__item' key={item.id || index}>
                <ImageComp src={src} onClick={() => preview(index)} isImage={isImage} extension={extension} />
                <Column className='pd-UploadFile__item__icon'>
                  {editable && <Icon name='close' color='red' size={36} onClick={() => del(index)} />}
                </Column>
              </View>
            );
          })}
          {canUpload && (
            <Column className='pd-UploadFile__item' justify='center' items='center' onClick={add}>
              <Text color={2} size={48}>
                <Icon name='add' />
              </Text>
              <Text color={2} size={18}>
                {btnLabel}
              </Text>
            </Column>
          )}
        </Grid>
      )}
      {listType === 'text' && (
        <>
          {canUpload && (
            <Button onClick={add} className='pd-UploadFile__textUploadBtn' type='primary' size='s'>
              {btnLabel}
            </Button>
          )}
          {state.selectedValue?.map((item, index) => {
            const src = item[urlField || valueField];
            return (
              <View className='pd-UploadFile__textItem flex-row' key={item.id || index}>
                <Icon name='attachent' size={36} onClick={() => preview(index)} />
                <Text grow numberOfLines={1} size={28} color={2} onClick={() => preview(index)}>
                  {extractFilename(src)}
                </Text>
                {editable && <Icon name='close' color='red' size={36} onClick={() => del(index)} />}
              </View>
            );
          })}
        </>
      )}
    </View>
  );
};

export default UploadFile;

function ImageComp({ src, onClick, isImage, extension, ...props }: ImageProps & { isImage?: boolean; extension?: string }) {
  const [isError, setIsError] = useState(false);
  useEffect(() => {
    setIsError(false);
  }, [src]);
  if (!isImage) {
    return (
      <View className='pd-UploadFile__item__image w-full h-full justify-center items-center' onClick={onClick}>
        <Text color={2} size={28}>
          {extension}
        </Text>
      </View>
    );
  }
  if (isError) {
    return (
      <View className='pd-UploadFile__item__image w-full h-full justify-center items-center' onClick={onClick}>
        <Text color={2} size={18}>
          显示失败:{extension}
        </Text>
      </View>
    );
  }
  return (
    <Image
      className='pd-UploadFile__item__image w-full h-full'
      src={src}
      mode='aspectFit'
      onError={e => {
        setIsError(true);
      }}
      {...props}
    />
  );
}
